package com.zhu.component.aop;

import com.zhu.component.CacheTemplate;
import com.zhu.component.annotation.ZCache;
import com.zhu.component.entity.Sku;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Slf4j
@Aspect
@Component
public class CacheAspect {

    @Autowired
    CacheTemplate cacheTemplate;

    @Pointcut("@annotation(com.zhu.component.annotation.ZCache)")
    public void pointCut(){}

    @Around("pointCut()")
    public Object doCache(ProceedingJoinPoint joinPoint){
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        try {
            Method method = joinPoint.getTarget().getClass().getMethod(signature.getName(),
                    signature.getMethod().getParameterTypes());
            ZCache annotation = method.getAnnotation(ZCache.class);
            String keyEL = annotation.key();
            // 获取方法参数值
            Object[] args = joinPoint.getArgs();
            // 获取方法的真实参数名
            DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
            String[] parameterNames = discoverer.getParameterNames(method);

            ExpressionParser parser = new SpelExpressionParser();
            Expression expression = parser.parseExpression(keyEL);
            StandardEvaluationContext context = new StandardEvaluationContext();

            for (int i = 0; i < parameterNames.length ; i++) {
                context.setVariable(parameterNames[i], args[i]);
            }
            String value = expression.getValue(context).toString();

            // query by redis
            Object cache = cacheTemplate.get(annotation.scope() + value);

            if (cache != null){
                log.info("query by cache");
                return cache;
            }
            cache = joinPoint.proceed();

            cacheTemplate.set(annotation.scope() + value, cache);

            return cache;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

        return null;
    }

}
